<i18n locale="en" lang="yaml">
lastStarted  : 'Started {t}'
lastSucceeded: 'Succeeded {t}'
lastFailed   : 'Failed {t}'
</i18n>

<i18n locale="zh-CN" lang="yaml">
Config     : 配置
Auth       : 认证
Task Record: 任务记录

Async API disabled: 异步 API 已禁用
Async API enabled : 异步 API 已启用
Async API deleted : 异步 API 已删除

Show all contents: 展示全部内容
No Async API has ever been added: 从未添加过任何异步 API

Are you sure you want to disable the Async API?: 是否确认禁用此异步 API？
Are you sure you want to delete the Async API?: 是否确认删除此异步 API？

lastStarted  : '{t}执行'
lastSucceeded: '{t}执行成功'
lastFailed   : '{t}执行失败'

Using Async APIs, you can execute long and time-consuming Python functions: 使用异步 API，可以执行长耗时的 Python 函数
</i18n>

<!-- Generated by OpenCC START -->
<i18n locale="zh-HK" lang="yaml">
Are you sure you want to delete the Async API?: 是否確認刪除此異步 API？
Are you sure you want to disable the Async API?: 是否確認禁用此異步 API？
Async API deleted: 異步 API 已刪除
Async API disabled: 異步 API 已禁用
Async API enabled: 異步 API 已啓用
Auth: 認證
Config: 配置
No Async API has ever been added: 從未添加過任何異步 API
Show all contents: 展示全部內容
Task Record: 任務記錄
Using Async APIs, you can execute long and time-consuming Python functions: 使用異步 API，可以執行長耗時的 Python 函數
lastFailed: '{t}執行失敗'
lastStarted: '{t}執行'
lastSucceeded: '{t}執行成功'
</i18n>
<i18n locale="zh-TW" lang="yaml">
Are you sure you want to delete the Async API?: 是否確認刪除此非同步 API？
Are you sure you want to disable the Async API?: 是否確認禁用此非同步 API？
Async API deleted: 非同步 API 已刪除
Async API disabled: 非同步 API 已禁用
Async API enabled: 非同步 API 已啟用
Auth: 認證
Config: 配置
No Async API has ever been added: 從未新增過任何非同步 API
Show all contents: 展示全部內容
Task Record: 任務記錄
Using Async APIs, you can execute long and time-consuming Python functions: 使用非同步 API，可以執行長耗時的 Python 函式
lastFailed: '{t}執行失敗'
lastStarted: '{t}執行'
lastSucceeded: '{t}執行成功'
</i18n>
<!-- Generated by OpenCC END -->

<template>
  <transition name="fade">
    <el-container direction="vertical" v-show="$store.state.isLoaded">
      <!-- Header area -->
      <el-header height="60px">
        <div class="common-page-header">
          <h1>{{ $t('Async API') }}</h1>
          <div class="header-control">
            <FuzzySearchInput :dataFilter="dataFilter"></FuzzySearchInput>

            <el-tooltip :content="$t('Show all contents')" placement="bottom" :enterable="false">
              <el-checkbox
                :border="true"
                size="small"
                v-model="dataFilter.origin"
                true-label="_ALL"
                false-label="user"
                @change="T.changePageFilter(dataFilter)">{{ $t('Show all') }}</el-checkbox>
            </el-tooltip>
            <el-button @click="openSetup(null, 'add')" type="primary" size="small">
              <i class="fa fa-fw fa-plus"></i>
              {{ $t('New') }}
            </el-button>
          </div>
        </div>
      </el-header>

      <!-- List area -->
      <el-main class="common-table-container">
        <div class="no-data-area" v-if="T.isNothing(data)">
          <h1 class="no-data-title" v-if="T.isPageFiltered({ ignore: { origin: '_ALL' } })"><i class="fa fa-fw fa-search"></i>{{ $t('No matched data found') }}</h1>
          <h1 class="no-data-title" v-else><i class="fa fa-fw fa-info-circle"></i>{{ $t('No Async API has ever been added') }}</h1>

          <p class="no-data-tip">
            {{ $t('Using Async APIs, you can execute long and time-consuming Python functions') }}
          </p>
        </div>
        <el-table v-else
          class="common-table" height="100%"
          :data="data"
          :row-class-name="common.getHighlightRowCSS">

          <el-table-column :label="$t('Func')" min-width="420">
            <template slot-scope="scope">
              <FuncInfo
                :config-func-id="scope.row.funcId"
                :id="scope.row.func_id"
                :title="scope.row.func_title"
                :kwargsJSON="scope.row.funcCallKwargsJSON" />

              <div>
                <span class="text-info">ID</span>
                &nbsp;<code class="text-main">{{ scope.row.id }}</code>
                <CopyButton :content="scope.row.id" />

                <template v-if="T.notNothing(scope.row.tagsJSON) || T.notNothing(scope.row.func_tagsJSON)">
                  <br>
                  <span class="text-info">&#12288;{{ $t('Tags') }}</span>
                  <el-tag size="mini" type="info" v-for="t in scope.row.func_tagsJSON" :key="t">{{ t }}</el-tag>
                  <el-tag size="mini" type="warning" v-for="t in scope.row.tagsJSON" :key="t">{{ t }}</el-tag>
                </template>

                <template v-if="scope.row.note">
                  <br>
                  <span class="text-info">&#12288;{{ $t('Note') }}{{ $t(':') }}</span>
                  <span>{{ scope.row.note }}</span>
                </template>
              </div>

              <InfoBlock v-if="scope.row.lastTaskStatus && scope.row.lastTaskStatus.exceptionTEXT"
                type="error" :title="scope.row.lastTaskStatus.exceptionTEXT" />
            </template>
          </el-table-column>

          <el-table-column :label="$t('Config')" width="255">
            <template slot-scope="scope">
              <span class="text-info">{{ $t('Queue') }}{{ $t(':') }}</span>
              <span>
                #{{ scope.row.func_extraConfigJSON.queue || $store.getters.SYSTEM_INFO('_FUNC_TASK_QUEUE_ASYNC_API') }}
              </span>

              <br>
              <span class="text-info">{{ $t('Timeout') }}{{ $t(':') }}</span>
              <span v-if="scope.row.func_extraConfigJSON && scope.row.func_extraConfigJSON.timeout">
                {{ $tc('nSeconds', scope.row.func_extraConfigJSON.timeout) }}
              </span>
              <template v-else>
                {{ $tc('nSeconds', $store.getters.SYSTEM_INFO('_FUNC_TASK_TIMEOUT_DEFAULT')) }}
              </template>

              <template v-if="!!scope.row.apia_id">
                <span class="text-info">{{ $t('Auth') }}{{ $t(':') }}</span>
                <el-tooltip :content="scope.row.apia_title" :disabled="!!!scope.row.apia_title" placement="right">
                  <span class="text-main">{{ C.API_AUTH_MAP.get(scope.row.apia_type).name }}</span>
                </el-tooltip>
              </template>

              <template v-if="scope.row.expireTime">
                <br>
                <span class="text-info">{{ $t('Expires') }}{{ $t(':') }}</span>
                <RelativeDateTime :datetime="scope.row.expireTime"
                  :class="T.isExpired(scope.row.expireTime) ? 'text-bad' : 'text-good'" />
              </template>

              <template v-if="T.notNothing(scope.row.throttlingJSON)">
                <br>
                <span class="text-info">{{ $t('Throttling') }}{{ $t(':') }}</span>
                <el-tooltip placement="right">
                  <div slot="content">
                    <template v-for="opt in C.SYNC_API_THROTTLING">
                      <span v-if="scope.row.throttlingJSON[opt.key]">{{ $tc(opt.name, scope.row.throttlingJSON[opt.key]) }}<br></span>
                    </template>
                  </div>
                  <span class="text-bad">{{ $t('ON') }}</span>
                </el-tooltip>
              </template>
            </template>
          </el-table-column>

          <el-table-column :label="$t('Status')" width="255">
            <template slot-scope="scope">
              <span v-if="scope.row.isDisabled" class="text-bad">
                <i class="fa fa-fw fa-ban"></i>
                {{ $t('Disabled') }}
              </span>
              <span v-else class="text-good">
                <i class="fa fa-fw fa-check"></i>
                {{ $t('Enabled') }}
              </span>

              <br>
              <el-tooltip placement="right" effect="dark" v-if="scope.row.lastTaskStatus">
                <div slot="content">
                  <span class="datetime-tip">{{ scope.row.lastTaskStatus.timestamp * 1000 | datetime }}</span>
                </div>
                <span v-if="scope.row.lastTaskStatus.status === 'started'" class="text-main">
                  <i class="fa fa-fw fa-circle-o-notch fa-spin"></i>
                  {{ $t('lastStarted', { t: T.toNow(scope.row.lastTaskStatus.timestamp * 1000) }) }}
                </span>
                <span v-else-if="scope.row.lastTaskStatus.status === 'success'" class="text-good">
                  <i class="fa fa-fw fa-check"></i>
                  {{ $t('lastSucceeded', { t: T.toNow(scope.row.lastTaskStatus.timestamp * 1000) }) }}
                </span>
                <span v-else-if="scope.row.lastTaskStatus.status === 'failure'" class="text-bad">
                  <i class="fa fa-fw fa-times"></i>
                  {{ $t('lastFailed', { t: T.toNow(scope.row.lastTaskStatus.timestamp * 1000) }) }}
                </span>
              </el-tooltip>
              <span v-else class="text-info">
                <i class="fa fa-fw fa-ellipsis-h"></i>
                {{ $t('No task record') }}
              </span>
            </template>
          </el-table-column>

          <el-table-column align="right" width="400">
            <template slot-scope="scope">
              <el-tooltip effect="dark" :content="scope.row.localFuncTaskRecordTip" placement="left" :disabled="!scope.row.localFuncTaskRecordTip">
                <el-badge class="task-record-button" type="primary" :max="99" :hidden="!funcTaskRecordCountMap[scope.row.id] || !scope.row.isLocalFuncTaskRecordAvailable" :value="funcTaskRecordCountMap[scope.row.id] && funcTaskRecordCountMap[scope.row.id].count || 0">
                  <el-link
                    @click="common.goToPage('task-record-func-list', { origin: 'asyncAPI', originId: scope.row.id }, { hlDataId: scope.row.id })"
                    :disabled="!scope.row.isLocalFuncTaskRecordAvailable">
                    {{ $t('Task Record') }}
                  </el-link>
                </el-badge>
              </el-tooltip>

              <el-link :disabled="T.isNothing(scope.row.func_id)" @click="showAPI(scope.row)">{{ $t('Example') }}</el-link>
              <el-link :disabled="T.isNothing(scope.row.func_id)" v-if="scope.row.isDisabled" v-prevent-re-click @click="quickSubmitData(scope.row, 'enable')">{{ $t('Enable') }}</el-link>
              <el-link :disabled="T.isNothing(scope.row.func_id)" v-if="!scope.row.isDisabled" @click="quickSubmitData(scope.row, 'disable')">{{ $t('Disable') }}</el-link>
              <el-link @click="openSetup(scope.row, 'setup')">{{ $t('Setup') }}</el-link>
              <el-link type="danger" @click="quickSubmitData(scope.row, 'delete')">{{ $t('Delete') }}</el-link>
            </template>
          </el-table-column>
        </el-table>
      </el-main>

      <!-- Paging area -->
      <Pager :pageInfo="pageInfo" />
      <AsyncAPISetup ref="setup" />

      <APIExampleDialog ref="apiExampleDialog"></APIExampleDialog>
    </el-container>
  </transition>
</template>

<script>
import AsyncAPISetup from '@/components/Management/AsyncAPISetup'
import APIExampleDialog from '@/components/APIExampleDialog'

export default {
  name: 'AsyncAPIList',
  components: {
    AsyncAPISetup,
    APIExampleDialog,
  },
  watch: {
    $route: {
      immediate: true,
      async handler(to, from) {
        await this.loadData();
      }
    },
    '$store.state.isLoaded': function(val) {
      if (!val) return;

      setImmediate(() => this.T.autoScrollTable());
    },
  },
  methods: {
    async loadData(options) {
      options = options || {};

      // Default filter
      let _listQuery = this.dataFilter = this.T.createListQuery();
      if (this.T.isNothing(this.$route.query)) {
        _listQuery.origin = 'user';
      }

      let apiRes = await this.T.callAPI_get('/api/v1/async-apis/do/list', {
        query: _listQuery,
      });
      if (!apiRes || !apiRes.ok) return;

      apiRes.data.forEach(d => {
        d.func_extraConfigJSON = d.func_extraConfigJSON || {};

        d.isLocalFuncTaskRecordAvailable = false;

        if (!this.isLocalFuncTaskRecordEnabled) {
          if (this.isGuanceDataUploadEnabled) {
            d.localFuncTaskRecordTip = this.$t('Local Func task record is disabled, while uploading to Guance is enabled');
          } else {
            d.localFuncTaskRecordTip = this.$t('Local Func task record is disabled');
          }

        } else if (!d.taskRecordLimit) {
          d.localFuncTaskRecordTip = this.$t('Number of recent task records to be kept is not specified');

        } else {
          d.isLocalFuncTaskRecordAvailable = true;
          if (this.isGuanceDataUploadEnabled) {
            d.localFuncTaskRecordTip = this.$t('Func task record uploading to Guance has also been enabled');
          }
        }
      });


      this.data = apiRes.data;
      this.pageInfo = apiRes.pageInfo;

      this.$store.commit('updateLoadStatus', true);

      // Get Task Record count info
      if (this.isLocalFuncTaskRecordEnabled && !options.skipStatistic) {
        this.isFuncTaskRecordCountLoaded = false;
        setTimeout(async () => {
          this.funcTaskRecordCountMap = await this.common.getFuncTaskRecordCountMap('originId', this.data.map(d => d.id));
          this.isFuncTaskRecordCountLoaded = true;
        }, 1000);
      }
    },
    async quickSubmitData(d, operation) {
      switch(operation) {
        case 'disable':
          if (!await this.T.confirm(this.$t('Are you sure you want to disable the Async API?'))) return;
          break;

        case 'delete':
          if (!await this.T.confirm(this.$t('Are you sure you want to delete the Async API?'))) return;
          break;
      }

      let apiRes = null;
      switch(operation) {
        case 'disable':
          apiRes = await this.T.callAPI('post', '/api/v1/async-apis/:id/do/modify', {
            params  : { id: d.id },
            body    : { data: { isDisabled: true } },
            feedback: { okMessage: this.$t('Async API disabled') },
          });
          break;

        case 'enable':
          apiRes = await this.T.callAPI('post', '/api/v1/async-apis/:id/do/modify', {
            params  : { id: d.id },
            body    : { data: { isDisabled: false } },
            feedback: { okMessage: this.$t('Async API enabled') },
          });
          break;

        case 'delete':
          apiRes = await this.T.callAPI('/api/v1/async-apis/:id/do/delete', {
            params  : { id: d.id },
            feedback: { okMessage: this.$t('Async API deleted') },
          });
          break;
      }
      if (!apiRes || !apiRes.ok) return;

      this.$store.commit('updateHighlightedTableDataId', d.id);

      await this.loadData({ skipStatistic: true });
    },
    openSetup(d, target) {
      switch(target) {
        case 'add':
          this.$refs.setup.loadData();
          break;

        case 'setup':
          this.$store.commit('updateHighlightedTableDataId', d.id);
          this.$refs.setup.loadData(d.id);
          break;
      }
    },
    async showAPI(d) {
      // Get Func info
      let apiRes = await this.T.callAPI_getOne('/api/v1/funcs/do/list', d.funcId);
      if (!apiRes || !apiRes.ok) return;

      // Gen API request example
      let apiURL = this.T.formatURL('/api/v1/async/:id', {
        baseURL: true,
        params : { id: d.id },
      });

      let funcCallKwargsJSON = {};
      for (let k in d.funcCallKwargsJSON) if (d.funcCallKwargsJSON.hasOwnProperty(k)) {
        if (this.common.isFuncArgumentPlaceholder(d.funcCallKwargsJSON[k])) {
          funcCallKwargsJSON[k] = d.funcCallKwargsJSON[k];
        }
      }
      let apiBody = { kwargs: funcCallKwargsJSON };
      let funcKwargs = apiRes.data.kwargsJSON;

      this.$refs.apiExampleDialog.update(apiURL, apiBody, funcKwargs);

      this.$store.commit('updateHighlightedTableDataId', d.id);
    },
  },
  computed: {
    isLocalFuncTaskRecordEnabled() {
      return !!this.$store.getters.SYSTEM_SETTINGS('LOCAL_FUNC_TASK_RECORD_ENABLED');
    },
    isGuanceDataUploadEnabled() {
      return !!this.$store.getters.SYSTEM_SETTINGS('GUANCE_DATA_UPLOAD_ENABLED');
    },
  },
  props: {
  },
  data() {
    let _pageInfo   = this.T.createPageInfo();
    let _dataFilter = this.T.createListQuery();

    return {
      data    : [],
      pageInfo: _pageInfo,

      funcTaskRecordCountMap     : {},
      isFuncTaskRecordCountLoaded: false,

      dataFilter: {
        _fuzzySearch: _dataFilter._fuzzySearch,
        origin      : _dataFilter.origin,
      },
    }
  },
  created() {
    this.$root.$on('reload.asyncAPIList', () => this.loadData({ skipStatistic: true }));
  },
  destroyed() {
    this.$root.$off('reload.asyncAPIList');
  },
}
</script>

<style scoped>
.task-record-button {
  margin-right: 15px;
}
.datetime-tip {
  font-size: 16px;
}
</style>

<style>
</style>
